using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Xml;

using LocalBoard.Domain;
using LocalBoard.Persistence;

using Rss;

namespace LocalBoard.Controller
{
	/// <summary>
	/// Summary description for RssController.
	/// </summary>
	public class RssController
	{
		private const int ShortMessageSize = 200;
		private IAccessorFactory _accessorFactory = null;

		private string _appName = "";
		private string _appLink = "";
		private string _appDescription = "";
		private string _appLanguage = "";
		private string _itemLinkTemplate = "";

		private RssFeed _rssFeed = null;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="appName">Application name</param>
		/// <param name="appLink">Application link</param>
		/// <param name="appDescription">Application description</param>
		/// <param name="appLanguage">Application language</param>
		/// <param name="itemLinkTemplate">Template to construct a link for each item (message)</param>
		/// <param name="accessorFactory">Accessor Factory</param>
		public RssController(string appName, string appLink, string appDescription, string appLanguage, string itemLinkTemplate, IAccessorFactory accessorFactory)
		{
			_appName = appName;
			_appLink = appLink;
			_appDescription = appDescription;
			_appLanguage = appLanguage;
			_itemLinkTemplate = itemLinkTemplate;
			_accessorFactory = accessorFactory;
		}

		/// <summary>
		/// Construct rss feed object from club.
		/// </summary>
		/// <param name="club"></param>
		public void ConstructRssFeed(Club club)
		{
			_rssFeed = constructRssFeed(club);
		}

		/// <summary>
		/// Construct rss xml from board.
		/// </summary>
		/// <param name="board"></param>
		public void ConstructRssFeed(Board board)
		{
			_rssFeed = constructRssFeed(board);
		}

		/// <summary>
		/// Write Rss feed to any kind of stream. You should construct rss feed before by calling <see cref="ConstructRssFeed">ConstructRssFeed</see> method
		/// </summary>
		/// <param name="stream"></param>
		public void WriteRss(Stream stream)
		{
			CheckIfRssFeedConstructed();
			_rssFeed.Write(stream);
		}

		/// <summary>
		///  Write Rss feed to file. You should construct rss feed before by calling <see cref="ConstructRssFeed">ConstructRssFeed</see> method
		/// </summary>
		/// <param name="filename"></param>
		public void WriteRss(string filename)
		{
			CheckIfRssFeedConstructed();
			_rssFeed.Write(filename);
		}

		#region Helper
		private void CheckIfRssFeedConstructed()
		{
			if(_rssFeed == null)
				throw new ApplicationException("You should construct rss feed before by calling 'ConstructRssFeed' method");
		}

		private RssFeed constructRssFeed(object clubObject)
		{
			RssFeed rssFeed = new RssFeed();
			rssFeed.Version = RssVersion.RSS20;

			rssFeed.Channels.Add(constructRssChannel(clubObject));
			return rssFeed;
		}

		private RssChannel constructRssChannel(object clubObject)
		{
			RssChannel rssChannel = new RssChannel();
			rssChannel.Title = _appName;
			rssChannel.Description = _appDescription.Length == 0 ? _appName : _appDescription;
			rssChannel.Link = new Uri(_appLink);
			rssChannel.PubDate = DateTime.Now;
			AddItemsFromClubObject(rssChannel, clubObject);
			return rssChannel;
		}

		private void AddItemsFromMessageList(RssChannel rssChannel, ArrayList messageList)
		{
			if(messageList.Count > 0)
			{
				foreach(Message message in messageList)
				{
					rssChannel.Items.Add(ConstructItemFromMessage(message));
				}
			}
			else
				rssChannel.Items.Add(ConstructDummyItem());
		}

		private ArrayList GetNewMessageList(BoardController boardController)
		{
			return boardController.GetMessageListForCurrentPage();
		}

		private void AddItemsFromClubObject(RssChannel rssChannel, object clubObject)
		{
			ClubController clubController = null;
			BoardController boardController = null;
			if(clubObject is Club)
			{
				clubController = new ClubController(((Club)clubObject).Id, _accessorFactory);
				boardController = new ClubBoardController(clubController, 0, _accessorFactory);
			}
			else if(clubObject is Board)
			{
				Board board = clubObject as Board;
				clubController = new ClubController(board.ClubId, _accessorFactory);
				boardController = new BoardController(board.Id, clubController, 0, _accessorFactory);
			}
			else
				throw new ArgumentException("Type not supported");

			ArrayList messageList = GetNewMessageList(boardController);
			AddItemsFromMessageList(rssChannel, messageList);
		}

		private RssItem ConstructItemFromMessage(Message message)
		{
			RssItem rssItem = new RssItem();
			rssItem.Author = message.PostedByUserName;
			rssItem.Title = message.Subject;
			rssItem.Description = message.Body.Substring(0, (IsMessageShort(message) ? message.Body.Length : ShortMessageSize)) + (IsMessageShort(message) ? "" : "...");
			rssItem.Link = new Uri(string.Format(_itemLinkTemplate, message.ClubId, message.BoardId, message.Id));
			rssItem.PubDate = message.Date;

			return rssItem;
		}

		private RssItem ConstructDummyItem()
		{
			RssItem rssItem = new RssItem();
			rssItem.Title = "No message posted yet";

			return rssItem;
		}

		private bool IsMessageShort(Message message)
		{
			return message.Body.Length < ShortMessageSize;
		}
		#endregion
	}
}
